Skip to content

Improve project view status handling - #10

Merged
roodboi merged 5 commits into
mainfrom
squircle
Feb 19, 2026
Merged

Improve project view status handling#10
roodboi merged 5 commits into
mainfrom
squircle

Conversation

@roodboi

@roodboi roodboi commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • tighten project-view status derivation and representations so dashboard components display runtime health more reliably
  • align macOS dashboard views and status strip with the updated models/commands for clearer gateway/runtime feedback
  • add regression coverage for the project view helpers to prevent stale status logic from slipping back in

Testing

  • Not run (not requested)

Summary by CodeRabbit

  • New Features

    • Sessions section in dashboard displaying active, attached, and detached sessions with attach and stop controls
    • Expandable titlebar status strip for quick project access
    • Persistent hooks tracking to show startup and shutdown commands that remain running
    • External terminal integration for session attachment with preferences saved
  • Changes

    • Daemon now auto-starts on login by default; use --no-run-at-load to disable
  • Documentation

    • Updated daemon installation instructions

@changeset-bot

changeset-bot Bot commented Feb 19, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: f06f84c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@roodboi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 15 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

Configuration and UI updates to the hack daemon and macOS dashboard. Changes include defaulting launchd auto-start behavior, repositioning the status strip in the titlebar, adding expandable session selector panel, implementing session attachment to external terminals, and tracking lifecycle command persistence across the codebase.

Changes

Cohort / File(s) Summary
Launchd Default Behavior
.hack/hack.config.json, README.md, docs/cli.md, src/control-plane/sdk/config.ts, tests/control-plane-config.test.ts
Daemon now defaults to auto-start on login (runAtLoad: true). Updated installation instructions and CLI documentation accordingly.
Dashboard Layout and Status Strip
apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/DashboardView.swift, apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/GlobalStatusStrip.swift
Repositioned GlobalStatusStrip from toolbar to main content area with titlebar alignment. Added hover-driven expandable selector panel with project list and status indicators in titlebar mode. Updated iconography to use NSColor.labelColor.
Session Management Feature
apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/HomeDashboardView.swift
Added Sessions section to dashboard with session grouping (active/attached/detached), external terminal preferences, and attach actions. Implemented session-to-terminal attachment with support for tmux and zellij backends.
Lifecycle Persistence Tracking
apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/ProjectDetailView.swift, apps/macos/Packages/Shared/Models/Sources/HackDesktopModels/Models.swift, src/commands/projects.ts, src/lib/project-views.ts, tests/project-views.test.ts
Added persistent flag to lifecycle commands and hooks. Tracks persistent hook counts separately. Updated UI to display persistent badges and summary counts.
Docker Proxy Configuration
examples/templates/global/caddy.compose.yml, src/templates.ts, tests/coredns-config.test.ts
Caddy service now explicitly runs docker-proxy with 5-second polling interval configuration.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Dashboard as HomeDashboardView
    participant Session as SessionRow
    participant Terminal as TerminalIntegration
    participant Notifications as NotificationCenter

    User->>Dashboard: Click Attach on session
    Dashboard->>Session: Show attach menu
    User->>Session: Select terminal (Hack/External)
    Session->>Dashboard: attachSession(entry, terminal)
    
    alt Hack Terminal
        Dashboard->>Notifications: Post hackTerminalOpenRequested
        Notifications-->>Terminal: Handle open request
    else External Terminal
        Dashboard->>Dashboard: Build attach command (tmux/zellij)
        Dashboard->>Terminal: Open terminal with command
        Terminal-->>User: Display session in terminal
    end
    
    Dashboard->>Dashboard: Update preferredExternalTerminal
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 A dashboard now dances with sessions galore,
Status strips shift to the top, as never before,
Persistent hooks count with badges so bright,
Attach to your terminals—left, right, and tight! 🚀
Default launch waits, no flags needed, hooray!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'Improve project view status handling' is vague and does not accurately reflect the broad scope of changes across multiple systems including dashboard UI, terminal integration, persistent hooks, daemon launch configuration, and Docker proxy settings. Revise the title to be more specific about the primary change (e.g., 'Add project session management and persistent hooks tracking' or 'Enhance dashboard with session management and status indicators').
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch squircle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@roodboi
roodboi merged commit 4539e92 into main Feb 19, 2026
2 checks passed
@roodboi
roodboi deleted the squircle branch February 19, 2026 22:26
roodboi pushed a commit that referenced this pull request Feb 19, 2026
## <small>1.10.1 (2026-02-19)</small>

* Fix gateway 502 for livenation ([a1bb858](a1bb858))
* Improve dashboard header and groups ([1e58826](1e58826))
* Merge branch 'main' into squircle ([f06f84c](f06f84c))
* Merge pull request #10 from hack-dance/squircle ([4539e92](4539e92)), closes [#10](#10)
* fix(runtime): improve local ingress self-healing ([d305e2d](d305e2d))
* fix(tests): stabilize shell mocks across bun test suite ([402ebe2](402ebe2))

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/ProjectDetailView.swift (1)

137-141: ⚠️ Potential issue | 🟡 Minor

Header pill shows processCount but lifecycle badge shows persistentCount — inconsistent.

Line 140 uses lifecycleSummary.processCount for the "persistent" label, but line 812 uses lifecycleSummary.persistentCount (which equals persistentHookCount + processCount). If a project has persistent lifecycle hooks, the header pill will undercount.

🐛 Proposed fix
           if lifecycleSummary.hasEntries {
             headerMetricPill(
               "Startup",
-              value: "\(lifecycleSummary.startupHookCount) hooks / \(lifecycleSummary.processCount) persistent"
+              value: "\(lifecycleSummary.startupHookCount) hooks / \(lifecycleSummary.persistentCount) persistent"
             )
           }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/ProjectDetailView.swift`
around lines 137 - 141, The header pill for "Startup" uses
lifecycleSummary.processCount but the lifecycle badge uses
lifecycleSummary.persistentCount, causing undercounting; update the
headerMetricPill call in ProjectDetailView (the "Startup" label block that
currently formats "\(lifecycleSummary.processCount) persistent") to use
lifecycleSummary.persistentCount (which is persistentHookCount + processCount)
so both the header and the lifecycle badge report the same persistent total.
🧹 Nitpick comments (7)
src/templates.ts (1)

32-35: Consider using CADDY_DOCKER_POLLING_INTERVAL env var for consistency.

The existing CADDY_INGRESS_NETWORKS is already configured via the environment: block. The caddy-docker-proxy docs show CADDY_DOCKER_POLLING_INTERVAL=<duration> as the equivalent env var for the polling interval. Using the env var keeps all runtime configuration in one place and avoids the need to override command: (which replaces the image's default CMD).

♻️ Alternative using env var (no command block needed)
-    "    command:",
-    "      - docker-proxy",
-    "      - --polling-interval",
-    "      - 5s",
     "    ports:",
...
     "    environment:",
     `      CADDY_INGRESS_NETWORKS: ${DEFAULT_INGRESS_NETWORK}`,
+    "      CADDY_DOCKER_POLLING_INTERVAL: 5s",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/templates.ts` around lines 32 - 35, Replace the explicit command override
for docker-proxy with the equivalent environment variable: remove the "command:"
array entries (the docker-proxy/--polling-interval/5s lines) and instead add an
environment variable CADDY_DOCKER_POLLING_INTERVAL set to the desired duration
alongside the existing CADDY_INGRESS_NETWORKS in the environment block so
runtime config remains consistent and the image default CMD is preserved.
tests/coredns-config.test.ts (1)

27-39: Command block assertions are tied to the static-IP test case, but the block is unconditional.

The command: / docker-proxy block in renderGlobalCaddyCompose is emitted regardless of useStaticCaddyIp / useStaticCoreDnsIp. Bundling these assertions into the static-IP test provides no coverage for the default render path. Consider adding a dedicated test or a simple standalone assertion:

♻️ Suggested additional test for the default render path
test("renderGlobalCaddyCompose always includes docker-proxy command", () => {
  const text = renderGlobalCaddyCompose();
  expect(text).toContain("command:");
  expect(text).toContain("- docker-proxy");
  expect(text).toContain("- --polling-interval");
  expect(text).toContain("- 5s");
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/coredns-config.test.ts` around lines 27 - 39, The test currently
couples assertions for the unconditional "command:/docker-proxy" block with the
static-IP case, leaving the default render path untested; update tests to either
extract the docker-proxy assertions into a separate test that calls
renderGlobalCaddyCompose() with no args (e.g., a new test
"renderGlobalCaddyCompose always includes docker-proxy command") or move those
assertions out of the static-IP test so the static-IP test only asserts
IP/network lines (references: renderGlobalCaddyCompose, DEFAULT_CADDY_IP,
DEFAULT_COREDNS_IP). Ensure the new/adjusted test verifies "command:", "-
docker-proxy", "- --polling-interval", and "- 5s" are present.
apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/GlobalStatusStrip.swift (3)

858-883: Corner radius reset task uses a hardcoded delay that differs from the named constant pattern.

collapseSelectorPanel uses 140_000_000 nanoseconds directly (line 873) while other delays are defined as named computed properties (e.g., selectorCloseDelayNanoseconds). For consistency, consider extracting this into a named property.

♻️ Proposed fix
+  private var selectorCornerResetDelayNanoseconds: UInt64 {
+    140_000_000
+  }
+
   private func collapseSelectorPanel() {
     ...
     selectorCornerResetTask = Task {
-      try? await Task.sleep(nanoseconds: 140_000_000)
+      try? await Task.sleep(nanoseconds: selectorCornerResetDelayNanoseconds)
       ...
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/GlobalStatusStrip.swift`
around lines 858 - 883, The collapseSelectorPanel function contains a hardcoded
sleep delay (140_000_000 ns) for selectorCornerResetTask; replace this literal
with a named computed property (e.g., selectorCornerResetDelayNanoseconds or
reuse an existing selectorCloseDelayNanoseconds if appropriate) and use that
property in the Task.sleep call, update any related comments/tests to reference
the new constant, and ensure the property is declared near other timing
properties so the timing pattern remains consistent across
selectorExpand/collapse logic.

571-583: RelativeDateTimeFormatter is allocated on every computed property access.

This computed property creates a new RelativeDateTimeFormatter each time the view body evaluates. Consider making it a static let or caching it to avoid repeated allocation.

♻️ Proposed fix: hoist formatter to static
+  private static let relativeFormatter: RelativeDateTimeFormatter = {
+    let f = RelativeDateTimeFormatter()
+    f.unitsStyle = .abbreviated
+    return f
+  }()
+
   private var lastUpdatedText: String? {
     guard let date = model.lastUpdated else { return nil }
-    let formatter = RelativeDateTimeFormatter()
-    formatter.unitsStyle = .abbreviated
     let now = Date()
     if date > now {
       return "Updated just now"
     }
     let delta = now.timeIntervalSince(date)
     if delta < 5 {
       return "Updated just now"
     }
-    return "Updated \(formatter.localizedString(for: date, relativeTo: now))"
+    return "Updated \(Self.relativeFormatter.localizedString(for: date, relativeTo: now))"
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/GlobalStatusStrip.swift`
around lines 571 - 583, The computed property lastUpdatedText repeatedly
allocates a RelativeDateTimeFormatter on every access; change to use a shared,
lazily-initialized formatter (e.g. a static let or cached instance) so the
formatter is reused. Locate lastUpdatedText and replace the local "let formatter
= RelativeDateTimeFormatter()" with a reference to the shared formatter (ensure
its unitsStyle = .abbreviated is set when creating the static), keep the same
logic using model.lastUpdated, Date(), and timeIntervalSince(date), and ensure
thread-safety by using a static let or a DispatchOnce-style lazy initializer.

15-25: Consider grouping related hover/expansion state into a dedicated struct or observable.

Ten @State properties for a single hover-expand interaction add cognitive load. While functional, extracting them into a small SelectorExpansionState struct (or a lightweight observable) would improve readability and make it easier to reason about the state machine.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/GlobalStatusStrip.swift`
around lines 15 - 25, Group the closely related hover/expand state
(isSelectorHeaderHovered, isSelectorPanelHovered, isSelectorExpanded,
isSelectorListVisible, selectorUsesExpandedCorners, hoveredSelectorProjectId,
selectorExpandTask, selectorCollapseTask, selectorListRevealTask,
selectorCornerResetTask, stripContentWidth) into a single small model (e.g.,
struct SelectorExpansionState or class SelectorExpansionModel: ObservableObject)
and replace the individual `@State` properties in GlobalStatusStrip with one
`@StateObject` or `@ObservedObject` instance; update all references and bindings to
use the new model’s properties (and expose any Task handlers as methods on the
model if needed), ensuring SwiftUI updates work the same way and that
initialization and lifecycle (creation, cancelation of tasks) are handled inside
the new model.
apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/HomeDashboardView.swift (2)

449-456: DashboardSessionEntry synthesizes Hashable over full model objects.

The struct holds ProjectSessionSummary and optional ProjectSummary, so synthesized Hashable will hash all their fields. This is fine for typical project counts but worth noting — if these models grow large, consider implementing Hashable manually using just the id.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/HomeDashboardView.swift`
around lines 449 - 456, DashboardSessionEntry currently derives Hashable for the
full session and project models which will hash all fields; change this to a
manual, ID-based hash by removing the synthesized Hashable conformance and
implementing Hashable (and Equatable) where hash(into:) only feeds session.id
and project?.id (or use the existing id property) and equality compares the same
IDs; update the type declaration for DashboardSessionEntry and add the
hash(into:) and == implementations referencing session.id and project?.id to
avoid hashing large model contents.

309-323: attachCommand and shellQuote are duplicated from ProjectDetailView.

Both attachCommand(for:) (lines 309–316) and shellQuote(_:) (lines 318–323) are identical to their counterparts in ProjectDetailView.swift (lines 1898–1905 and 1932–1937). Additionally, SettingsOverlayView.swift has a shellQuote with a different escaping strategy ('\'' vs '"'"'), which could cause subtle inconsistencies if one is used over the other.

Consider extracting these into a shared utility (e.g., on TerminalIntegration or a small helper extension) to avoid divergence.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/HomeDashboardView.swift`
around lines 309 - 323, Duplicate implementations of attachCommand(for:) and
shellQuote(_:) exist across HomeDashboardView, ProjectDetailView, and a variant
in SettingsOverlayView; extract a single shared implementation (for example as
static helpers on TerminalIntegration or a small ShellQuote helper) and replace
the duplicated methods with calls to that shared API. Move the tmux/zellij logic
from attachCommand(for:) and the robust escaping used in shellQuote(_:) into the
new helper, update HomeDashboardView.attachCommand(for:) and
ProjectDetailView.attachCommand(for:) to call the shared function, and
consolidate SettingsOverlayView to use the same escaping strategy to avoid
divergence.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/HomeDashboardView.swift`:
- Around line 370-378: HomeDashboardView currently falls back to
TerminalIntegration.ExternalTerminalApp.hackDesktop while ProjectDetailView
falls back to .terminal, causing inconsistent defaults for the same `@AppStorage`
keys; either align them or document the intentional difference. Fix by locating
the preferredExternalTerminal computed property in HomeDashboardView (using
preferredExternalTerminalRaw and legacyPreferredExternalTerminalRaw) and either
change the final return from .hackDesktop to .terminal to match
ProjectDetailView, or add a clear code comment above the property explaining why
HomeDashboardView intentionally uses .hackDesktop and referencing
ProjectDetailView’s fallback to .terminal so future readers know this divergence
is deliberate.

---

Outside diff comments:
In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/ProjectDetailView.swift`:
- Around line 137-141: The header pill for "Startup" uses
lifecycleSummary.processCount but the lifecycle badge uses
lifecycleSummary.persistentCount, causing undercounting; update the
headerMetricPill call in ProjectDetailView (the "Startup" label block that
currently formats "\(lifecycleSummary.processCount) persistent") to use
lifecycleSummary.persistentCount (which is persistentHookCount + processCount)
so both the header and the lifecycle badge report the same persistent total.

---

Nitpick comments:
In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/GlobalStatusStrip.swift`:
- Around line 858-883: The collapseSelectorPanel function contains a hardcoded
sleep delay (140_000_000 ns) for selectorCornerResetTask; replace this literal
with a named computed property (e.g., selectorCornerResetDelayNanoseconds or
reuse an existing selectorCloseDelayNanoseconds if appropriate) and use that
property in the Task.sleep call, update any related comments/tests to reference
the new constant, and ensure the property is declared near other timing
properties so the timing pattern remains consistent across
selectorExpand/collapse logic.
- Around line 571-583: The computed property lastUpdatedText repeatedly
allocates a RelativeDateTimeFormatter on every access; change to use a shared,
lazily-initialized formatter (e.g. a static let or cached instance) so the
formatter is reused. Locate lastUpdatedText and replace the local "let formatter
= RelativeDateTimeFormatter()" with a reference to the shared formatter (ensure
its unitsStyle = .abbreviated is set when creating the static), keep the same
logic using model.lastUpdated, Date(), and timeIntervalSince(date), and ensure
thread-safety by using a static let or a DispatchOnce-style lazy initializer.
- Around line 15-25: Group the closely related hover/expand state
(isSelectorHeaderHovered, isSelectorPanelHovered, isSelectorExpanded,
isSelectorListVisible, selectorUsesExpandedCorners, hoveredSelectorProjectId,
selectorExpandTask, selectorCollapseTask, selectorListRevealTask,
selectorCornerResetTask, stripContentWidth) into a single small model (e.g.,
struct SelectorExpansionState or class SelectorExpansionModel: ObservableObject)
and replace the individual `@State` properties in GlobalStatusStrip with one
`@StateObject` or `@ObservedObject` instance; update all references and bindings to
use the new model’s properties (and expose any Task handlers as methods on the
model if needed), ensuring SwiftUI updates work the same way and that
initialization and lifecycle (creation, cancelation of tasks) are handled inside
the new model.

In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/HomeDashboardView.swift`:
- Around line 449-456: DashboardSessionEntry currently derives Hashable for the
full session and project models which will hash all fields; change this to a
manual, ID-based hash by removing the synthesized Hashable conformance and
implementing Hashable (and Equatable) where hash(into:) only feeds session.id
and project?.id (or use the existing id property) and equality compares the same
IDs; update the type declaration for DashboardSessionEntry and add the
hash(into:) and == implementations referencing session.id and project?.id to
avoid hashing large model contents.
- Around line 309-323: Duplicate implementations of attachCommand(for:) and
shellQuote(_:) exist across HomeDashboardView, ProjectDetailView, and a variant
in SettingsOverlayView; extract a single shared implementation (for example as
static helpers on TerminalIntegration or a small ShellQuote helper) and replace
the duplicated methods with calls to that shared API. Move the tmux/zellij logic
from attachCommand(for:) and the robust escaping used in shellQuote(_:) into the
new helper, update HomeDashboardView.attachCommand(for:) and
ProjectDetailView.attachCommand(for:) to call the shared function, and
consolidate SettingsOverlayView to use the same escaping strategy to avoid
divergence.

In `@src/templates.ts`:
- Around line 32-35: Replace the explicit command override for docker-proxy with
the equivalent environment variable: remove the "command:" array entries (the
docker-proxy/--polling-interval/5s lines) and instead add an environment
variable CADDY_DOCKER_POLLING_INTERVAL set to the desired duration alongside the
existing CADDY_INGRESS_NETWORKS in the environment block so runtime config
remains consistent and the image default CMD is preserved.

In `@tests/coredns-config.test.ts`:
- Around line 27-39: The test currently couples assertions for the unconditional
"command:/docker-proxy" block with the static-IP case, leaving the default
render path untested; update tests to either extract the docker-proxy assertions
into a separate test that calls renderGlobalCaddyCompose() with no args (e.g., a
new test "renderGlobalCaddyCompose always includes docker-proxy command") or
move those assertions out of the static-IP test so the static-IP test only
asserts IP/network lines (references: renderGlobalCaddyCompose,
DEFAULT_CADDY_IP, DEFAULT_COREDNS_IP). Ensure the new/adjusted test verifies
"command:", "- docker-proxy", "- --polling-interval", and "- 5s" are present.

Comment on lines +370 to +378
private var preferredExternalTerminal: TerminalIntegration.ExternalTerminalApp {
if let explicit = TerminalIntegration.ExternalTerminalApp(rawValue: preferredExternalTerminalRaw) {
return explicit
}
if let legacy = TerminalIntegration.ExternalTerminalApp(rawValue: legacyPreferredExternalTerminalRaw) {
return legacy
}
return .hackDesktop
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, find the HomeDashboardView file and check the specified lines
find . -name "HomeDashboardView.swift" -type f

Repository: hack-dance/hack

Length of output: 155


🏁 Script executed:

# Find ProjectDetailView.swift file
find . -name "ProjectDetailView.swift" -type f

Repository: hack-dance/hack

Length of output: 155


🏁 Script executed:

# Search for all preferredExternalTerminal properties and their fallbacks
rg -n 'preferredExternalTerminal' --type=swift -A 10 -B 2

Repository: hack-dance/hack

Length of output: 25036


Default terminal inconsistency: .hackDesktop vs .terminal — clarify or align.

HomeDashboardView falls back to .hackDesktop while ProjectDetailView falls back to .terminal (line 1803). Both use the same @AppStorage keys with .terminal initialization, yet diverge in their final fallback. Add a code comment explaining the intentional difference, or align both to use the same fallback.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/macos/Packages/Features/DashboardFeature/Sources/DashboardFeature/HomeDashboardView.swift`
around lines 370 - 378, HomeDashboardView currently falls back to
TerminalIntegration.ExternalTerminalApp.hackDesktop while ProjectDetailView
falls back to .terminal, causing inconsistent defaults for the same `@AppStorage`
keys; either align them or document the intentional difference. Fix by locating
the preferredExternalTerminal computed property in HomeDashboardView (using
preferredExternalTerminalRaw and legacyPreferredExternalTerminalRaw) and either
change the final return from .hackDesktop to .terminal to match
ProjectDetailView, or add a clear code comment above the property explaining why
HomeDashboardView intentionally uses .hackDesktop and referencing
ProjectDetailView’s fallback to .terminal so future readers know this divergence
is deliberate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant